/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package org.eclipse.iota.model;

import static org.eclipse.iota.arithmetics.IotaOperationExecutor.add;
import static org.eclipse.iota.arithmetics.IotaOperationExecutor.multiply;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.impl.EObjectImpl;
import org.eclipse.iota.IotaPackage;
import org.eclipse.iota.arithmetics.IotaFactorExtractor;
import org.eclipse.iota.arithmetics.IotaOffsetExtractor;

/**
 * @see org.eclipse.iota.IotaPackage#getLinearExpression()
 * @model kind="class"
 * @generated
 */
public class LinearExpression extends EObjectImpl implements HighLevelExpression {
	
	/**
	 * Alternative constructor.
	 * @param factor Factor of the linear expression.
	 * @param base Base of the linear expression.
	 * @param offset The offset of the linear expression.
	 * @generated NOT
	 */
	public LinearExpression(Constant factor, Expression base, Constant offset) {
		super();
		setFactor(factor);
		setBase(base);
		setOffset(offset);
	}

	/**
	 * Create a linear expression from an arbitrary expression.
	 * @param expression Expression.
	 * @return Linear version.
	 * @generated NOT
	 */
	public static LinearExpression fromBasic(Expression expression) {
		
		// Extract offset first:
		Constant offset = IotaOffsetExtractor.extractOffset(expression);
		Expression base = IotaOffsetExtractor.extractBase(expression);
		
		// Then the factor:
		Constant factor = IotaFactorExtractor.extractFactor(base);
		base = IotaFactorExtractor.extractBase(base);
		
		// Create the linear expression:
		return new LinearExpression(factor, base, offset);
		
	}
	
	/**
	 * Convert this linear expression to a basic one again.
	 * @model
	 * @generated NOT
	 */
	public Expression toBasic() {
		// Construct the basic expression:
		return add(multiply(getFactor().copy(), getBase()), getOffset());
	}
	
	/**
	 * Get the equation that owns this expression.
	 * @generated NOT
	 */
	public Equation basicGetEquation() {
		if (eContainer() instanceof Equation) return (Equation) eContainer();
		if (eContainer() instanceof Expression) return ((Expression) eContainer()).getEquation();
		return null;
	}
	
	/**
	 * @generated NOT
	 */
	@Override
	public String toString() {
		return getFactor() + "*" + getBase() + "+" + getOffset();
	}
	
	/* ---------------------------------------------------------------- *
	 * GENERATED CODE.                                                  *
	 * Do not edit below this line. If you need to edit, move it above  *
	 * this line and change the '@generated'-tag to '@generated NOT'.   *
	 * ---------------------------------------------------------------- */	
	
	/**
	 * The cached value of the '{@link #getBase() <em>Base</em>}' containment reference.
	 * @see #getBase()
	 * @generated
	 * @ordered
	 */
	protected Expression base;

	/**
	 * The cached value of the '{@link #getFactor() <em>Factor</em>}' containment reference.
	 * @see #getFactor()
	 * @generated
	 * @ordered
	 */
	protected Constant factor;

	/**
	 * The cached value of the '{@link #getOffset() <em>Offset</em>}' containment reference.
	 * @see #getOffset()
	 * @generated
	 * @ordered
	 */
	protected Constant offset;

	/**
	 * @generated
	 */
	public LinearExpression() {
		super();
	}

	/**
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return IotaPackage.Literals.LINEAR_EXPRESSION;
	}

	/**
	 * Returns the value of the '<em><b>Equation</b></em>' reference.
	 * @return the value of the '<em>Equation</em>' reference.
	 * @see org.eclipse.iota.IotaPackage#getExpression_Equation()
	 * @model transient="true" changeable="false" volatile="true" derived="true"
	 * @generated
	 */
	public Equation getEquation() {
		Equation equation = basicGetEquation();
		return equation != null && equation.eIsProxy() ? (Equation)eResolveProxy((InternalEObject)equation) : equation;
	}

	/**
	 * Returns the value of the '<em><b>Base</b></em>' containment reference.
	 * @return the value of the '<em>Base</em>' containment reference.
	 * @see #setBase(Expression)
	 * @see org.eclipse.iota.IotaPackage#getLinearExpression_Base()
	 * @model containment="true"
	 * @generated
	 */
	public Expression getBase() {
		return base;
	}

	/**
	 * @generated
	 */
	public NotificationChain basicSetBase(Expression newBase, NotificationChain msgs) {
		Expression oldBase = base;
		base = newBase;
		if (eNotificationRequired()) {
			ENotificationImpl notification = new ENotificationImpl(this, Notification.SET, IotaPackage.LINEAR_EXPRESSION__BASE, oldBase, newBase);
			if (msgs == null) msgs = notification; else msgs.add(notification);
		}
		return msgs;
	}

	/**
	 * Sets the value of the '{@link org.eclipse.iota.model.LinearExpression#getBase <em>Base</em>}' containment reference.
	 * @param value the new value of the '<em>Base</em>' containment reference.
	 * @see #getBase()
	 * @generated
	 */
	public void setBase(Expression newBase) {
		if (newBase != base) {
			NotificationChain msgs = null;
			if (base != null)
				msgs = ((InternalEObject)base).eInverseRemove(this, EOPPOSITE_FEATURE_BASE - IotaPackage.LINEAR_EXPRESSION__BASE, null, msgs);
			if (newBase != null)
				msgs = ((InternalEObject)newBase).eInverseAdd(this, EOPPOSITE_FEATURE_BASE - IotaPackage.LINEAR_EXPRESSION__BASE, null, msgs);
			msgs = basicSetBase(newBase, msgs);
			if (msgs != null) msgs.dispatch();
		}
		else if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, IotaPackage.LINEAR_EXPRESSION__BASE, newBase, newBase));
	}

	/**
	 * Returns the value of the '<em><b>Factor</b></em>' containment reference.
	 * @return the value of the '<em>Factor</em>' containment reference.
	 * @see #setFactor(Constant)
	 * @see org.eclipse.iota.IotaPackage#getLinearExpression_Factor()
	 * @model containment="true"
	 * @generated
	 */
	public Constant getFactor() {
		return factor;
	}

	/**
	 * @generated
	 */
	public NotificationChain basicSetFactor(Constant newFactor, NotificationChain msgs) {
		Constant oldFactor = factor;
		factor = newFactor;
		if (eNotificationRequired()) {
			ENotificationImpl notification = new ENotificationImpl(this, Notification.SET, IotaPackage.LINEAR_EXPRESSION__FACTOR, oldFactor, newFactor);
			if (msgs == null) msgs = notification; else msgs.add(notification);
		}
		return msgs;
	}

	/**
	 * Sets the value of the '{@link org.eclipse.iota.model.LinearExpression#getFactor <em>Factor</em>}' containment reference.
	 * @param value the new value of the '<em>Factor</em>' containment reference.
	 * @see #getFactor()
	 * @generated
	 */
	public void setFactor(Constant newFactor) {
		if (newFactor != factor) {
			NotificationChain msgs = null;
			if (factor != null)
				msgs = ((InternalEObject)factor).eInverseRemove(this, EOPPOSITE_FEATURE_BASE - IotaPackage.LINEAR_EXPRESSION__FACTOR, null, msgs);
			if (newFactor != null)
				msgs = ((InternalEObject)newFactor).eInverseAdd(this, EOPPOSITE_FEATURE_BASE - IotaPackage.LINEAR_EXPRESSION__FACTOR, null, msgs);
			msgs = basicSetFactor(newFactor, msgs);
			if (msgs != null) msgs.dispatch();
		}
		else if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, IotaPackage.LINEAR_EXPRESSION__FACTOR, newFactor, newFactor));
	}

	/**
	 * Returns the value of the '<em><b>Offset</b></em>' containment reference.
	 * @return the value of the '<em>Offset</em>' containment reference.
	 * @see #setOffset(Constant)
	 * @see org.eclipse.iota.IotaPackage#getLinearExpression_Offset()
	 * @model containment="true"
	 * @generated
	 */
	public Constant getOffset() {
		return offset;
	}

	/**
	 * @generated
	 */
	public NotificationChain basicSetOffset(Constant newOffset, NotificationChain msgs) {
		Constant oldOffset = offset;
		offset = newOffset;
		if (eNotificationRequired()) {
			ENotificationImpl notification = new ENotificationImpl(this, Notification.SET, IotaPackage.LINEAR_EXPRESSION__OFFSET, oldOffset, newOffset);
			if (msgs == null) msgs = notification; else msgs.add(notification);
		}
		return msgs;
	}

	/**
	 * Sets the value of the '{@link org.eclipse.iota.model.LinearExpression#getOffset <em>Offset</em>}' containment reference.
	 * @param value the new value of the '<em>Offset</em>' containment reference.
	 * @see #getOffset()
	 * @generated
	 */
	public void setOffset(Constant newOffset) {
		if (newOffset != offset) {
			NotificationChain msgs = null;
			if (offset != null)
				msgs = ((InternalEObject)offset).eInverseRemove(this, EOPPOSITE_FEATURE_BASE - IotaPackage.LINEAR_EXPRESSION__OFFSET, null, msgs);
			if (newOffset != null)
				msgs = ((InternalEObject)newOffset).eInverseAdd(this, EOPPOSITE_FEATURE_BASE - IotaPackage.LINEAR_EXPRESSION__OFFSET, null, msgs);
			msgs = basicSetOffset(newOffset, msgs);
			if (msgs != null) msgs.dispatch();
		}
		else if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, IotaPackage.LINEAR_EXPRESSION__OFFSET, newOffset, newOffset));
	}

	/**
	 * @generated
	 */
	@Override
	public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
		switch (featureID) {
			case IotaPackage.LINEAR_EXPRESSION__BASE:
				return basicSetBase(null, msgs);
			case IotaPackage.LINEAR_EXPRESSION__FACTOR:
				return basicSetFactor(null, msgs);
			case IotaPackage.LINEAR_EXPRESSION__OFFSET:
				return basicSetOffset(null, msgs);
		}
		return super.eInverseRemove(otherEnd, featureID, msgs);
	}

	/**
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case IotaPackage.LINEAR_EXPRESSION__EQUATION:
				if (resolve) return getEquation();
				return basicGetEquation();
			case IotaPackage.LINEAR_EXPRESSION__BASE:
				return getBase();
			case IotaPackage.LINEAR_EXPRESSION__FACTOR:
				return getFactor();
			case IotaPackage.LINEAR_EXPRESSION__OFFSET:
				return getOffset();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * @generated
	 */
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case IotaPackage.LINEAR_EXPRESSION__BASE:
				setBase((Expression)newValue);
				return;
			case IotaPackage.LINEAR_EXPRESSION__FACTOR:
				setFactor((Constant)newValue);
				return;
			case IotaPackage.LINEAR_EXPRESSION__OFFSET:
				setOffset((Constant)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case IotaPackage.LINEAR_EXPRESSION__BASE:
				setBase((Expression)null);
				return;
			case IotaPackage.LINEAR_EXPRESSION__FACTOR:
				setFactor((Constant)null);
				return;
			case IotaPackage.LINEAR_EXPRESSION__OFFSET:
				setOffset((Constant)null);
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case IotaPackage.LINEAR_EXPRESSION__EQUATION:
				return basicGetEquation() != null;
			case IotaPackage.LINEAR_EXPRESSION__BASE:
				return base != null;
			case IotaPackage.LINEAR_EXPRESSION__FACTOR:
				return factor != null;
			case IotaPackage.LINEAR_EXPRESSION__OFFSET:
				return offset != null;
		}
		return super.eIsSet(featureID);
	}

} // LinearExpression
